package com.adee.jdk8;

import java.util.Optional;

/*
*
* */
public class Test004_Optional {
    public static void main(String[] args) {
        // test();
        // test1();
        test2();
    }

    /*
    * Optional是一个容器对象，里面包含一个成员属性，通过这种方式来实现一种函数式编程风格。
    * */
    public static void test() {
        Optional<String> opt = Optional.of("hello");
        // 普通编程风格（不推荐）
        if(opt.isPresent()) {
            System.out.println(opt.get());
        }
        // 函数式变成风格
        opt.ifPresent(s -> System.out.println(s));

        Optional<Object> opt2 = Optional.empty();
        System.out.println(opt.orElse("default value")); // hello
        System.out.println(opt2.orElse("default value")); // default value
    }

    /*
    * 不可变类
    * https://blog.csdn.net/weixin_45902285/article/details/122636424
    * 不可变类：实例一旦创建后，不能改变其成员变量的值，这样的类称为不可变类，成员变量不可变指的是，基本类型的值
    * 不能变、对象类型引用不能变，数组类型元素不能变。
    *
    * java中的8中基本类型包装类和String类都是不可变类。
    *
    * 优点：
    * 1. 效率高
    *    对象拷贝不需要拷贝内容，只需要引用；
    * 2. 线程安全
    *    由于对象中成员变量不可变，因此是线程安全的。
    * 缺点：
    * 1. 每次"改变"都会产生新对象，会产生很多垃圾，增加垃圾收集器的压力。
    *
    * 不可变类的设计要素：
    * 1. 类被final修饰，防止子类继承。如果类可以被继承会破坏类的不可变性机制，只要继承类覆盖父类的方法并且继承类可以
    * 改变成员变量值，那么一旦子类以父类的形式出现时，不能保证当前类是否可变;
    * 2. 类中的属性都是final类型的，不能更改，还必须是private的，防止引用属性的内部被更改，防止泄漏地址；
    * 3. 没有setter方法更改属性，且getter方法不能返回原本的属性或对象，应该复制一份返回，因为怕把引用泄漏给外部，导
    * 致成员中的内容被修改。如String类的toCharArray方法，不会直接返回char[] value给外部，防止value数组中的元素
    * 被更改 ；
    * 4. 修改对象的属性时要返回新的对象，如subString方法;
    * 5. 对构造器传入的值，应该是拷贝一份，而不是用原本的值，如果使用传入的参数直接赋值，则传递的只是引用，仍然可以通过
    * 外部变量改变参数的的值，从而间接修改不可变类的值。
    *
    * 不可变类的应用：享元模式
    * 为了避免浪费，可以把这些不可变类的对象进行缓存，如果需要使用到的对象和缓存中的一致可以直接使用缓存中的已经创建好的
    * 对象，共享使用，因为是对象都是不可变的，所以相互共享也没什么毛病。这种共享不可变的对象是享元设计模式的一种实现。
    * 享元模式举例：
    * 在JDK中Boolean，Byte，Short，Integer，Long，Character等包装类提供了valueOf方法，例如Integer的valueOf会
    * 缓存-128~127（默认）之间的Integer对象，在这个范围之间会重用对象，大于这个范围，才会新建Integer对象。
    *
    *
    * */
    /*
    反编译后代码：
        public static void test1() {
            System.out.println("hello ");
            String s1 = new String("hello");
            String s2 = s1.intern();
            String s4 = "hello".intern();
            System.out.println("hello" == s1);
            System.out.println("hello" == s2);
            System.out.println("hello" == "hello");
            System.out.println("hello" == s4);
            System.out.println(s1 == s2);
            System.out.println(s1 == "hello");
            System.out.println(s1 == s4);
            System.out.println(s2 == "hello");
            System.out.println(s2 == s4);
            System.out.println("hello" == s4);
        }

    * */
    public static void test1() {
        String str = "hello ";
        System.out.println(str);
        // s被编译器内联优化（类似于宏替换），即代码中所有用到s的地方，编译时被替换为"hello"，s变量被优化掉，不存在了
        String s = "hello"; // 常量池中，字符串字面量加载时，在常量池中创建一个对象（String就是不可变类，对象也就是不可变对象）
        String s1 = new String("hello"); // 堆中，但s1.value成员变量依然指向常量池对象s.value，共享private int[] value;
        String s2 = s1.intern(); // 常量池中
        String s3 = "hello" + ""; // 编译器编译时内联优化为：String s3 = "hello";
        String s4 = s3.intern(); // 常量池中
        System.out.println(s == s1); // false
        System.out.println(s == s2); // true
        System.out.println(s == s3); //    true
        System.out.println(s == s4); // true
        System.out.println(s1 == s2); // false
        System.out.println(s1 == s3); // false
        System.out.println(s1 == s4); // false
        System.out.println(s2 == s3); //    true
        System.out.println(s2 == s4); // true
        System.out.println(s3 == s4); // true
    }

    /*
    * 在JDK中Boolean，Byte，Short，Integer，Long，Character等包装类提供了valueOf方法，例如Integer
    * 的valueOf会缓存-128~127（默认）之间的Integer对象，在这个范围之间会重用对象，大于这个范围，才会新建
    * Integer对象。
    * */
    /*
    反编译后代码：
    public static void test2() {
        Integer i2 = 10;
        int i3 = i2.intValue();
        System.out.println(i3);
        Integer i4 = 10;
        int i5 = i4.intValue();
        System.out.println(i5);
        System.out.println(10 == i2.intValue());
        Integer i6 = new Integer(12);
        Integer i7 = new Integer(12);
        System.out.println(i6 == i7);
    }
    * */
    public static void test2() {
        int i1 = 10; // 字面量直接赋值给变量，会被内联优化
        Integer i2 = Integer.valueOf(i1); // 装箱
        int i3 = i2.intValue(); // 拆箱
        System.out.println(i3);
        Integer i4 = i1; // 编译时自动装箱
        int i5 = i4; // 编译时自动拆箱
        System.out.println(i5);
        System.out.println(i1 == i2); // true int类型和Integer类型变量作比较时，先将Integer变量自动拆箱：
        Integer i6 = new Integer(12);
        Integer i7 = new Integer(12);
        System.out.println(i6 == i7); // false，Integer.valueOf方法会使用缓存，但是直接new Integer不会使用缓存
        // Integer i8 = null;
        // int i9 = i8; // 抛出空指针异常，自动拆箱会调用对象的intValue()方法，null对象调用任何方法都会抛出空指针异常
        // System.out.println(i9);
    }
}
